Sauvegarde automatisé en Bash

Tags:: bash :: ftp :: dedibox :: linux

On m'a demandé hier soir sur un canal IRC comment je procédais à ma sauvegarde sur Dedibox via le FTP distant mis à disposition. L'idée étant de transmettre sur le FTP distant des fichiers à sauvegarder et ce régulièrement...

Il existe des programmes de sauvegardes assez complets à paramétrer et configurer, mais étant donnée le peu de répertoire que je cherche à sauver, je ne voyais pas trop l'intérêt dans mon cas. Un simple script bash bien bricolé peut suffir, et c'est ce que je vais vous montrer.

Nous allons créer un petit script bash qui va créer une archive de nos données à sauvegarder (www et un dump Mysql), puis se connecte au FTP et envoit les fichiers. L'automatisation des sauvegardes de fichier n'est pas le plus compliqué, là où on commence à se poser des questions c'est le moment où il faut se connecter au FTP, s'authentifier et envoyer les fichiers...

Voilà donc la solution que j'ai trouvé. Elle n'est pas parfaite, mais elle a le mérite de fonctionner.

Archivage des fichiers

Commençons par le début, l'idée est de faire un .tar, ou tar.gz ou tag.bz2 (appelé tarball) de nos répertoires à sauver. Pour /var/www nous ferons, dans notre script, quelque chose du genre:


#on crée un répertoire de sauvegarde temporaire
mkdir -p /tmp/save_dir
#on entre dedans
cd /tmp/savedir

#puis on archive nos données
tar cf www.tar /var/www
#si nous voulions le compresser en gz (plus lent):
#tar cfz www.tar.gz /var/www
#ou en bz2 (encore plus compressé, mais encore plus lent)
#tar cfj www.tar.bz2 /var/www

 

L'option "cf" veut dire "compress in file". L'option "z" signifie "gzip", et "j" signifie "bz2". C'est dans la page de man de ma commande tar que vous pouvez trouver ces informations.

Cela crée donc une archive de notre répertoire /var/www.

Dump de MySQL

Passons au dump mysql, une commande permet de créer une archive des données au format SQL: mysqldump.

Remplacez user par votre nom d'utilisateur mysql qui a le plus de droits, et donnez le mot de passe à la place de password:


mysqldump -u user -p password
 

On peut redirriger la sortie dans un fichier afin de sauvegarder tout ça:


mysqldump -u user -p password > /tmp/savedir/mysqldump.sql
 

Sauf que voilà... j'ai pas mal de bases de données et je préfèrerai les séparer à raison de un fichier SQL par base. Donc, par exemple, si j'ai une base "Foo" je devrai faire:


mysqldump -u user -p password Foo > /tmp/savedir/mysqldump.Foo.sql
 

Sauf que je ne veux pas m'amuser à changer mon script de sauvegarde chaque fois que je crée ou que je supprime une base... Il faut donc automatiser aussi la récupération des noms de base de données et envoyer la commande mysqldump pour chacune d'elle. C'est en fait plus simple que vous ne le pensez.

Mysql vous afficher les noms de bases de données via la commande "show databases;", il suffit de faire ceci pour s'en rendre compte:


echo "show databases;" | mysql-u user -p password
Database
Foo
Bar
Baz
 

Aïe... zut... j'ai "Database" qui apparait mais c'est en fait le nom de la colonne qui apparait pour ma demande... "Database" n'est pas une base... et bien on va la supprimer de la sortie avec sed:


echo "show databases;" | mysql-u user -p password | sed "s/Database//"

Foo
Bar
Baz
 

Beaucoup mieux! Bon, pour chaque élement de la liste on va sauver notre base dans un fichier...


#je crée un répertoire pour mes bases et j'y entre
mkdir -p /tmp/save_dir/dbs
cd /tmp/save_dir/dbs

#je récupère la liste:
DBS=`echo "show databases;" | mysql-u <user> -p <password> | sed "s/Database//"`
for db in $DBS
do
     mysqldump -u user -p password $db > $db.sql
done
 

Reste à compresser le répertoire:


#on remonte d'un cran dans les répertoires:
cd ..
#ou alors directment
#cd /tmp/save_dir

#on compresse
tar cf dbs.tar dbs
#ou en tar.gz
#tar cfz dbs.tar.gz dbs
#ou en bz2
#tar cfj dbs.tar.gz dbs
 

Envoit au FTP

Voilà, en ce qui concerne la récupération des données et leur archivage, c'est bon... Reste à nous connecter au FTP, s'authentifier, puis envoyer les données. Il va falloir user d'une astuce pour envoyer les commandes ftp. On va imaginer qu'on utilise le FTP de Dedibox, adaptez cela à votre guise pour d'autres FTP.

Normalement, en mode "interactif", nous devrions faire, :


[root@sd-XXXXX ~]# ftp dedibackup.dedibox.fr
Connected to dedibackup2.dedibox.fr.
220-
Je backup ...
  __                                  _   
 /  )  _  _/  '  /  _  _  /           _) 
/(_/  (- (/  /  () (/ (  /( (/  /)   /__ 
                               /         
                             ... donc je suis
 
Espace disque  : 40To                   
En cas de difficulte de connexion, contactez
l'assistance technique Dedibox
 
RAPPEL : Les uploads ne sont pas autorises
depuis une adresse IP externe au reseau Dedibox.
 
220 Bienvenue sur Dedibackup 2 - Identifiez-vous
530 login first
530 login first
KERBEROS_V4 rejected as an authentication type
 

Arrrive alors l'invite de commande FTP, on nous demande un login (ici par exemple "sd-XXXX") et un mot de passe à taper quand on nous le demande:


Name (dedibackup.dedibox.fr:root): sd-XXXX
331 Mot de passe obligatoire
Password: (je tape mon mot de passe)
230 Identifiants Dedibackup acceptes
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
 

Tout est interactif... automatiser cela parait compliqué... en fait... non. Il suffit d'envoyer le flux de commande à la volée. On la refait... d'abord sortez de l'invite ftp en tapant quit


ftp> quit
221 A bientot
[root@sd-XXXXX ~]#
 

Regardez:


# ftp -i -n dedibackup.dedibox.fr << EOF
quote user sd-XXXX
quote pass MON_MOT_DE_PASSE
quit
EOF
 

Ok, on a quitté après authentification et on revient à l'invite de commande du Shell. Les option "-i" et "-n" font respectivement "couper le mode interactif" et "utilise l'auto-login".

Donc, si nous somme dans le répertoire de sauvegarde, on pourrait envoyer le dump MySQL pour tester:


# ftp -i -n dedibackup.dedibox.fr << EOF
quote user sd-XXXX
quote pass MON_MOT_DE_PASSE
put dbs.tar
quit
EOF
 

Après un petit moment, le fichier se retrouve sur le ftp...

Premier script simple

Bien. On récapitule:

  • on sait archiver notre répertoire /var/www
  • on sait dumper les bases mysql
  • on sait se connecter au FTP et envoyer un fichier.

Il serait bon de ne pas écraser nos sauvegardes, et donc de garder une sauvegarde par jour. On va donc "dater" nos fichiers, par exemple en leur donnant un nom qui contient la date.

Allons-y, on regarde ce que propose Linux pour afficher une date.:


# date
jeu oct  9 23:36:59 CEST 2008
 

Un peu long comme nom, et puis avec les espaces on va avoir du mal à "échapper" tout ça... sachant que nous utilisons une sauvegarde par jour, l'heure ne nous importe pas... et il serait préférable d'avoir une date au forma "Ymd" (Anneée sur 4 chiffre, mois sur deux chiffre et jour sur deux chiffre). Donc d'avoir en résultat pour le 9 octobre 2008: "20081009".

Un petit tour dans la page de man de la commande date et on trouve ce que nous cherchons.


# date +"%Y%m%d"
20081009
 

J'ai donc ce qu'il me faut pour commencer un bon script... attention la suite n'est pas le script définitif, allez jusqu'au bout de l'article !!!

Voilà, donc un premier scrip qui peut marcher:


#!/bin/bash
DATE=`date +"%Y%m%d"`
MYSQLUSER="myuser"
MYSQLPASS="mypass"
MYSQLOPTS="-u $MYSQLUSER -p $MYSQLPASS"
FTPSERVER="dedibackup.dedibox.fr"
FTPUSER="sd-XXXXX"
FTPPASSWD="MON_MOT_DE_PASSE"


#cette commande crée les répertoire save_dir et mysqldump
mkdir -p /tmp/save_dir/mysqldump

tar cf www.$DATE.tar /var/www

#dump des bases
DBS=`echo "show databases;" | mysql $MYSQLOPTS | sed "s/Database//"`
for db in DBS
do
     mysqldump $MYSQLOPTS > mysqldump/$db.sql
done

#archivage des dumps
tar cf mysqldump.$DATE.tar mysqldump


ftp -i -n $FTPSERVER << EOF
quote user $FTPUSER
quote pass $FTPPASSWD
put www.$DATE.tar
put mysqldump.$DATE.tar
quit
EOF

#Reste à supprimer le répertoire temporaire que vous utilisé
#pour les sauvegarde après le transfère:
cd /tmp
rm -rf /tmp/save_dir

 

Second script amélioré

Ceci fonctionne très bien... sauf que voilà... Après un certain temps, votre espace FTP va réduire, réduire... et réduire tellement que vous n'aurez plus de place. Dedibox m'offre 5Go d'espace, croyez moi ça se rempli très vite. J'ai donc décidé de ne garder que 2 ou 3 jours de sauvegardes. Il faut donc trouver le moyen de supprimer les fichiers du FTP qui ont une date inférieur à 2 jours.

Comme nous nommons nos fichier avec la date, cela va être très très simple. Seul souci: trouver comment avoir la date datant de deux jours, en gérant les mois de 30, 31, 28 ou 29 jours... Et encore une fois, la page de man de la commande date nous donne la solution. L'option "-d" nous permet de taper littéralement (en anglais) ce que nous cherchons.


# date
jeu oct  9 11:51:51 CEST 2008
# date -d "-2 day"
mar oct  7 11:51:40 CEST 2008
# date -d "-2 day" +"%Y%m%d"
20081007
 

Donc, maintenant, on peut faire:


# [... snip ...]
OLD=`date -d "-2 day" +"%Y%m%d"`
# [... snip ...]
ftp -i -n $FTPSERVER << EOF
quote user $FTPUSER
quote pass $FTPPASSWD
delete www.$OLD.tar
delete mysqldump.$OLD.tar
put www.$DATE.tar
put mysqldump.$DATE.tar
quit
EOF

#Reste à supprimer le répertoire temporaire que vous utilisé
#pour les sauvegarde après le transfère:
cd /tmp
rm -rf /tmp/save_dir


 

Ce qui a pour effet de supprimer le fichier qui a la date du jour moins 2 jours.

Crontab pour automatiser

Automatiser ceci dans un crontab. Posez votre script de sauvegarde dans /usr/local/bin et rendez le exécutable:


chmod +x /usr/local/bin/save.sh
 

Puis tapez:


#Pour changer d'éditeur si vous ne comprennez rien à vi (vim), et que vous préférez "nano":
#EDITOR="nano"

crontab -e
 

Vous arrivez sur l'édition du "crontab", on va imaginer que nous voulons sauvegarder toutes les nuits à 4h00 du matin:


0 4 * * * /usr/local/bin/save.sh >> /var/log/savesystem
 

Enregistrez le fichier, puis relancez crontab:


/etc/init.d/crond restart
 

Script complet

Pour terminer, voici ce que j'utilise sur ma Dedibox:


#!/bin/bash
echo "Process save begin at `date`"

#FTP Auth
FTPSERVER="dedibackup.dedibox.fr"
FTPUSER="sd-XXXXX"
FTPPASSWD="MOT_DE_PASSE"


#MySQL Auth
MYSQLUSER="MySQLUser"
MYSQLPASSWD="MySQLPassword"

#number days to keep save files
NBRDAYS=2

# ----- PROCESS SAVE -----

#don't touch this
LASTDATE=`date -d "-$NBRDAYS day" +"%Y%m%d"`
DATETIME=`date +"%Y%m%d"`
PASSMYSQL="-u$MYSQLUSER -p$MYSQLPASSWD"
WWW="www.$DATETIME.tar"
MYSQLDUMP="mysqldump.$DATETIME.tar"

LASTMYSQL="mysqldump.$LASTDATE.tar"
LASTWWW="www.$LASTDATE.tar"

#create save directories
mkdir -p /tmp/save_dir/mysql
#go to /tmp
cd /tmp/save_dir

echo "Tar www..."
tar cf $WWW /var/www

#dump sql
echo "dump databases"
DBS=`echo "show databases;" | mysql $PASSMYSQL | sed "s/Database//"`
for db in $DBS
do
        echo "dumping $db..."
        mysqldump $PASSMYSQL "$db" > mysql/$db.sql
done

tar cvf $MYSQLDUMP mysql
ftp -i -n $FTPSERVER << ENDF
quote user $FTPUSER
quote pass $FTPPASSWD
delete $LASTMYSQL
delete $LASTWWW
put $MYSQLDUMP
put $WWW
quit
ENDF

cd /tmp
rm -rf save_dir
echo "Save ended at `date`"
 

Ce qui me permet de sauvegarder 2 jours de données. Vous pouvez changer le nombre de jours en haut dans la variable "NBRDAYS". N'oubliez pas de changer les login et mot de passe de MySQL et FTP, ainsi que l'adresse du serveur FTP que vous utilisez.

Utilisez le code barre pour ouvrir le ticket dans votre mobile:
This ticket on you mobile
1 Vendredi 10 Octobre 2008 21:44:25, Guillaume

Voici un script qui pourrait se révéler fort utile.
J'espère qu'il fonctionne bien, parce que si j'ai besoin de cet articles dans plusieurs années, il a intérêt à être toujours là ! :)

2 Dimanche 12 Octobre 2008 18:42:48, Metal3d

T'en fais pas, il marchera aussi longtemps que tar, ftp et bash existeront :)

3 Vendredi 31 Octobre 2008 10:57:36, Xate

Tout cela est bien intéressant, mais il y a un point qui me fait tiquer. Cette ligne :
echo "show databases;" | mysql -u user -p password | sed "s/Database//"

On peut se passer de tous ces pipes, et autre appel à sed.

Tout d'abord, il s'agit de demander à MySQL d'exécuter une commande. Coup de bol, ils y ont pensé ! Je propose donc l'option '-e' :
mysql -u root -p -e "show databases;"

Reste que le retour n'est pas formaté de la manière la plus exploitable possible.
Je propose '-B' pour rendre la chose exploitable, et '-s' pour virer le nom des colonnes. Au final, on obtient :

[root@plaisyr_nds_a root]# mysql -u root -p -e "show databases;" -B -s
Enter password:
information_schema
AGS_Historique
mysql
test
[root@plaisyr_nds_a root]#


Mieux, non ?

4 Vendredi 31 Octobre 2008 12:03:26, Metal3d

Bien joué Xate et merci. Effectivement bien plus joli et bien mieux en terme de lisibilité

Je vais te citer dans le billet et corriger le script.

5 Mercredi 01 Avril 2009 21:45:05, onimura

Merci ce fut tres pedagogique et interressant !! encore merci!
@+

6 Mercredi 28 Octobre 2009 17:00:13, jean

Merci beaucoup pour ce script, qui tombe à point car je travaille actuellement sur les sauvegardes.
Ce qui m'embete, ce sont les mots de passe qui apparaissent en clair dans le bash ! Cela ne me paraît pas très prudent.
Y-a-t-il un moyen d'éviter cela ?

Bonne continuation et encore merci.

Jean

7 Mercredi 07 Septembre 2011 14:10:16, nierdz

Impeccable ce petit script.
Je n'avais pas envie de me creuser la tête à en écrire un moi même. T'es le premier sur la recherche google que j'ai faite et je vais pouvoir adapter ça à ma situation sans me prendre la tête sur la gestion des dates.
Merci beaucoup !

Ajouter un commentaire
Veuillez répondre à la question suivante : Tapez en minuscule le nom de l'animal qui fait wouaf wouaf

Trackbacks

Pour ajouter un trackback (retrolien) sur ce ticket, utilisez cette adresse: http://www.metal3d.org/index.php/trackback/default/tb?id=blog%2F130

Tags

Blog Copix Communication PC Config Fedora Vidéo Humour Autre Web Materiel Informatique PHP Développement Mootools HTML Linux WEB IE CSS Vista Microsoft Sympa XHTML Quizz Widget Klik CWE Voeux Bonne année Musique CCRMA Son Audio MAO Reconnaissance vocale Windows Mac Compiz MacOS Mysql Sun Base de données BD Screenlets Screenlet RPM compiz Ubuntu Live FireFox Derambarsh Facebook media informations Sécurité javascript SSH Commande Marketing concours ipod wii QT Trooltech Nokia Libre Logiciels GPL Attali Gnome Dock Compiler Bench undelete reiserfs recovery recover Thread Serveur Optimisation Server Apache Album RSS Flash Air XML Firefox Blender Opensource Orange Internet LiveBox Animaux Droits Logiciels Libres Google Loi RBS netcat Bash Téléphone Spam 3D NIDIA Standards Widgets Merise UML Streaming Developpement Perl MySQL Firewall Parfeu Bayes Novell Réseau Python LVS Salon FTP Dedibox Chrome Administration IRC Gentoo troll video Nouveauté Finance Etudiant spéctacle OpenOffice Javascript Java Info Eclpise ATI design mootools KDE Bureau Design GNU C Pages Jaunes Fun Bijoux Art mail Admin vmware fedora linux VirtualBox VMWare Qemu KVM vim Grep Fglrx Webkit GTK google web JQuery Coup de gueule coup de gueule Lois SVG Raycaster Canvas Hadopi Desktop Jeux Les Sims développement astuces Screen firefox Mobile Safaru Wine bash commande astuce Wave ooc C++ C# Netbook Hercules Bureautique Twitter Safari W3C chrome kazehakaze midori navigateur gecko webkit Links Liens Pyhon Nouvelles Metal Perso Conférence JDLL PCC Roadsend OOC News Acteur Cinéma Chanteur Seven windows orthographe pcc php jdll Slide Application mysql Html twitter python screen curses SVN Android Gphone iPhone OpenGL MindMap Projet Javascrtip Ajax Guitare Tab Tablature JSON firebug Chromium Iphone Titanium music sound android ogg ogv streaming Arkyne svn subversion gnome VLC Tv encoder ffmpeg Cryptage apple microsoft HTML5 Max Apple code youtube quvi git uzbl webgl chromium

  Catalogue professionnel de musique libre


  • twitter entries...
follow me on Twitter

Valid XHTML 1.0 Strict

tumblr visitor